LAMP之PHP的初始配置

1. PHP的配置文件

虽然PHP是以httpd的一个模块的形式存在的,但是PHP本身也有自己的配置文件,那就是php.ini。在前面安装时,我们已经拷贝了一个php.ini文件到/usr/local/php/etc/目录下面,这是我们已经知道了php.ini所在的路径在哪里。但有时候我们并不知道php.ini所在路路径,这时候就需要通过命令来查一查在哪里:

1
2
3
[root@localhost ~]# /usr/local/php/bin/php -i | grep -i "loaded configuration file"
Loaded Configuration File => /usr/local/php/etc/php.ini
PHP Warning: Unknown: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in Unknown on line 0

通过上面的查找可以看出php.ini的绝对路径为/usrl/local/php/etc/php.ini,下面的Warning为警告信息,可以忽略。若是想取消这个警告需要编辑php.ini,找到date.timezone设置如下:

1
date.timezone = Asia/Shanghai

再次执行将不再提示警告信息:

1
2
[root@localhost ~]# /usr/local/php/bin/php -i | grep -i "loaded configuration file"
Loaded Configuration File => /usr/local/php/etc/php.ini


2. PHP的disable_functions

PHP有很多内置的函数,有一些函数(比如exec)会直接调取Linux系统命令,如果开放将会非常危险。因此,基于安全考虑应该把一些存在安全风险的函数禁掉。一般我们应该禁掉的函数的配置改成如下即可,打开php.ini,搜索disable_functions并改成这样子:disable_functions = eval,assert,popen,passthru,escapeshellarg,escapeshellcmd,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_get_status,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,readlink,symlink,leak,popepassthru,stream_socket_server,proc_open,proc_close

关于这些所列出来的函数,暂时不用细究,将来遇到问题要记得曾经禁用掉了一些函数,这些被禁掉的函数是不能在PHP代码中调用的。更改完php.ini后,由于需要在httpd中调用PHP,所以需要重启httpd服务使其生效。


3. 配置error_log

PHP的日志对于程序员来讲非常重要,它是排查问题的重要手段。设置PHP错误日志,有诸多步骤:

1
2
3
4
5
6
7
8
9
# vim /usr/local/php/etc/php.ini
#<==搜索log_errors,改成如下
log_errors = On
#<==搜索error_log,改为
error_log = /var/log/php/php_errors.log
#<==搜索error_reporting,改为
error_reporting = E_ALL & ~E_NOTICE
#<==搜索display_error,改为
display_error = Off

上述配置文件说明:

  • log_errors可以设置为OnOff,如果想让PHP记录错误日志,需要设置为On
  • error_log设定错误日志路径。
  • error_reporting设定错误日志的级别,E_ALL为所有类型的日志,不管是提醒还是警告都会记录。在开发环境下面设置为E_ALL,可以方便程序员排查问题,但也会造成日志记录很多无意义的内容。&符号表示并且,|表示或者,~表示排除,所以& ~两个组合在一起E_ALL & ~E_NOTICE就是在E_ALL的基础上排除掉notice相关的日志。
  • 正常情况下在业务正常时只有上面的日志级别即可,如果是在开发时检测错误,需要设置为E_ALL | E_NOTICE`会显示更多的错误信息。
  • 注意,不同版本中这个日志级别可能会不一样,所以要根据提示来设置正确合适的日志级别。
  • display_errors设置为On,则会把错误日志直接显示在浏览器里,这样对于用户访问来说体验不好,而且还会暴露网站的一些文件路径等重要信息,所以要设置为Off

设置完php.ini后,还需要做一些额外的操作:

1
2
3
4
[root@localhost ~]# mkdir /var/log/php
[root@localhost ~]# chmod 777 /var/log/php/
#<==需要保证PHP的错误日志所在目录存在,并且权限为可写。
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful

下面是测试过程:

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost ~]# vim /data/wwwroot/www.123.com/test.php
#<==写入如下内容,故意把后面的分号;丢掉
<?php
echo 111
[root@localhost ~]# curl -A "123" -I -x127.0.0.1:80 www.123.com/test.php
HTTP/1.0 500 Internal Server Error
Date: Fri, 09 Mar 2018 08:45:30 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
X-Powered-By: PHP/5.6.34
Connection: close
Content-Type: text/html; charset=UTF-8

可以看到这里的状态码为500,这说明我们访问的页面是存在错误的,此时需要查看PHP的错误日志来判断错误的原因,如下:

1
2
[root@localhost ~]# cat /var/log/php/php_errors.log
[09-Mar-2018 16:45:30 Asia/Shanghai] PHP Parse error: syntax error, unexpected end of file, expecting ',' or ';' in /data/wwwroot/www.123.com/test.php on line 3

查看PHP的错误日志,有一条错误的记录,通过日志可以判断,test.php文件的第三行少了分号。


4. 配置open_basedir

一个服务器上跑很多网站,这是几乎所有小公司为节省成本采用的做法,但这样做也会有一些弊端:多个网站跑在同一服务器上,如果其中一个网站被黑,很有可能连累到其它的站点。为了避免这种尴尬的事情发生,我们应当做一些预防手段。

好在PHP有一个概念叫做open_basedir,它的作用是讲网站限定在指定目录里,就算该站点被黑了,骇客也只能在该目录下面作为,而不能左右其它的目录。如果你的服务器上只有一个站点,那可以直接在php.ini中设置open_basedir参数。但是如果服务器上跑的站点比较多,那在php.ini中设置就不合适了,因为在php.ini中只能定义一次,也就是说所有站点都一起定义限定的目录,那这样似乎起不到隔离多个站点的目的。

4.1. php.ini中设置open_basedir

在php.ini中设置open_basedir:

1
2
3
[root@localhost ~]# vim /usr/local/php/etc/php.ini
#<==搜索open_basedir,改成如下内容,并保存退出
open_basedir = /tmp:/data/wwwroot/www.123.com

上述配置的说明:

  • open_basedir可以是多个目录,用:分隔

接下来验证一下open_basedir的作用,因为已经限制PHP只能在/tmp和/fata/wwwroot/www.123.com两个目录下面活动,所以这次拿aming.com来演示:

1
2
3
4
5
6
7
8
9
[root@localhost ~]# /usr/local/apache2.4/bin/apachectl graceful
[root@localhost ~]# cp /usr/local/apache2.4/htdocs/1.php /data/wwwroot/aming.com/
[root@localhost ~]# curl -x127.0.0.1:80 -I aming.com/1.php
HTTP/1.0 500 Internal Server Error
Date: Fri, 09 Mar 2018 09:06:46 GMT
Server: Apache/2.4.29 (Unix) PHP/5.6.34
X-Powered-By: PHP/5.6.34
Connection: close
Content-Type: text/html; charset=UTF-8

由上述演示发现aming.com/1.php确实不能访问了,状态码为500,所以查看一下错误日志,得到信息如下:

1
2
3
[09-Mar-2018 17:06:46 Asia/Shanghai] PHP Warning: Unknown: open_basedir restriction in effect. File(/data/wwwroot/aming.com/1.php) is not within the allowed path(s): (/tmp:/data/wwwroot/www.123.com) in Unknown on line 0
[09-Mar-2018 17:06:46 Asia/Shanghai] PHP Warning: Unknown: failed to open stream: Operation not permitted in Unknown on line 0
[09-Mar-2018 17:06:46 Asia/Shanghai] PHP Fatal error: Unknown: Failed opening required '/data/wwwroot/aming.com/1.php' (include_path='.:/usr/local/php/lib/php') in Unknown on line 0

4.2. 虚拟主机配置中设置open_basedir

下面的设置是给单个虚拟主机配置open_basedir。对于php.ini里面的配置,在虚拟主机的配置文件中也是可以配置的:

1
2
3
4
5
6
7
8
9
[root@localhost ~]# vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf
#<==编辑成如下:
<VirtualHost *:80>
DocumentRoot "/data/wwwroot/www.123.com"
ServerName www.123.com
ServerAlias 123.com
CustomLog "|/usr/local/apache2.4/bin/rotatelogs -l logs/123.com-access_%Y%m%d.log 86400" combined
php_admin_value open_basedir "/data/wwwroot/www.123.com/:/tmp/" #<==就是这一行配置
</VirtualHost>

上述配置内容的说明:

  • 起作用的就是这一句:php_admin_value,它可以定义php.ini里面的参数,除此之外像error_log之类的也可以定义。
  • 在所要限制的目录后面一定要加斜杠来表示精确的匹配。

这样就可以实现,一个虚拟主机定义一个open_basedir。


5. PHP动态模块安装

编辑httpd时,有涉及动态和静态模块,其实PHP也一样有这种说法。在记录PHP安装的学习笔记中,所有的模块全部都为静态,并没有任何动态的模块。所谓动态,就是一个独立存在的.so文件,在httpd中php就是以动态模块的形式被加载的。

首先,应该学会查看PHP都加载了哪些功能模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[root@localhost ~]# /usr/local/php/bin/php -m
[PHP Modules]
bz2
Core
ctype
date
dom
ereg
exif
fileinfo
filter
gd
hash
iconv
json
libxml
mbstring
mcrypt
mysql
openssl
pcre
PDO
pdo_sqlite
Phar
posix
Reflection
session
SimpleXML
soap
sockets
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib
[Zend Modules]

PHP和核心文件为/usr/local/php/bin/php,针对apache的是/usr/local/apache2.4/modules/libphp5.so模块。这两个文件是核心,我们在编译PHP的时候会提前让它支持一些功能,比如支持mysql,这个功能其实是PHP的一个模块,只不过这个模块是直接和PHP或者libphp5.so文件编译在一起的。当我们编译完PHP后,发现我们还需要让PHP支持另外的模块,即要想再增加一个功能模块的话,要么重新编译PHP,要么直接编译一个扩展模块(即生成一个.so文件),然后在php.ini中配置一下,让PHP去调用它,就可以被加载使用了。

下面是两个示例:

5.1. 示例1:安装redis扩展模块

下载redis扩展模块安装包并解压:

1
2
3
4
5
[root@localhost ~]# cd /usr/local/src/
[root@localhost src]# wget https://codeload.github.com/phpredis/phpredis/zip/develop
[root@localhost src]# mv develop phpredis-develop.zip
[root@localhost src]# unzip !$
[root@localhost src]# cd phpredis-develop

下面是安装步骤:

1
2
3
4
5
6
7
[root@localhost phpredis-develop]# /usr/local/php/bin/phpize
Configuring for:
PHP Api Version: 20131106
Zend Module Api No: 20131226
Zend Extension Api No: 220131226
Cannot find autoconf. Please check your autoconf installation and the
$PHP_AUTOCONF environment variable. Then, rerun this script.

这一步的作用是生产configure文件,但是在这一步并没有执行成功,可以看到有一个错误:Cannot find autoconf,这需要安装autoconf:yum install -y autoconf,然后再次执行该步骤:

1
2
3
4
5
6
7
8
9
[root@localhost phpredis-develop]# /usr/local/php/bin/phpize
Configuring for:
PHP Api Version: 20131106
Zend Module Api No: 20131226
Zend Extension Api No: 220131226
[root@localhost phpredis-develop]# ./configure --with-php-config=/usr/local/php/bin/php-config
[root@localhost phpredis-develop]# make
[root@localhost phpredis-develop]# make install
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-zts-20131226/

上述步骤的说明:

  • make install的时候会把编译好的redis.so放到这个目录下面:/usr/local/php/lib/php/extensions/no-debug-zts-20131226,这个目录也是扩展模块存放目录。
  • 查看扩展模块存放目录的方法:/usr/local/php/bin/php -i | grep extension_dir我们也可以在php.ini中自定义该目录

接下来是在php.ini中添加调用模块的配置:

1
2
3
[root@localhost phpredis-develop]# vim /usr/local/php/etc/php.ini
#<==添加一行配置,可以放到文件最后一行
extension = redis.so

然后查看是否加载了redis模块:

1
2
[root@localhost phpredis-develop]# /usr/local/php/bin/php -m | grep redis
redis

到此,PHP的redis模块就安装和配置成功了。

5.2. 示例2:安装memcache扩展模块

下载memcache模块安装包:

1
2
[root@localhost phpredis-develop]# cd /usr/local/src/
[root@localhost src]# wget http://pecl.php.net/get/memcache-3.0.8.tgz

安装memcache模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost src]# tar zxf memcache-3.0.8.tgz
[root@localhost src]# cd memcache-3.0.8
[root@localhost memcache-2.2.3]# /usr/local/php/bin/phpize
[root@localhost memcache-2.2.3]# ./configure --with-php-config=/usr/local/php/bin/php-config
[root@localhost memcache-2.2.3]# make
[root@localhost memcache-3.0.8]# echo $?
0
[root@localhost memcache-3.0.8]# make install
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-zts-20131226/
#<==查看已安装模块
[root@localhost memcache-3.0.8]# ll /usr/local/php/lib/php/extensions/no-debug-zts-20131226/
总用量 2696
-rwxr-xr-x 1 root root 464145 39 18:42 memcache.so
-rwxr-xr-x 1 root root 555981 36 23:42 opcache.so
-rwxr-xr-x 1 root root 1732634 39 18:21 redis.so

配置php.ini文件以使PHP调用模块:

1
2
3
4
5
6
[root@localhost phpredis-develop]# vim /usr/local/php/etc/php.ini
#<==添加一行配置,可以放到文件最后一行
extension = memcache.so
#<==保存退出后查看PHP是否成功加载了该模块:
[root@localhost memcache-3.0.8]# /usr/local/php/bin/php -m | grep memcache
memcache

至此,memcache模块安装成功。

加入,我们把安装的模块放在了自定义的扩展模块存放目录里面,那该如何配置呢?示例如下:

1
2
3
[root@localhost ~]# vim /usr/local/php/etc/php.ini
#<==编辑php.ini文件,查找extension_dir,并添加一条配置成如下:
extension_dir = "/usr/local/php/ext"

保存退出后我们做一下测试:

1
2
3
4
5
6
7
[root@localhost ~]# mkdir /usr/local/php/ext
[root@localhost ~]# mv /usr/local/php/lib/php/extensions/no-debug-zts-20131226/memcache.so /usr/local/php/ext/
[root@localhost ~]# /usr/local/php/bin/php -m | grep memcache
memcache
[root@localhost ~]# /usr/local/php/bin/php -i | grep extension_dir
extension_dir => /usr/local/php/ext => /usr/local/php/ext
sqlite3.extension_dir => no value => no value

通过上述测试我们知道,存放在我们自定义的模块存放目录下的memcache模块能被调用,并且用命令查看模块存放目录也是我们所自定义的目录,这说明我们配置成功了。


如果以后遇到增加模块的需求,都可以按照上面两个例子的步骤和方法来安装。另外,要想在PHP网站上面使用新安装的模块,还需要重启一下httpd服务。

0%